/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.put.netbeans.dcs_modeler;

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import org.netbeans.api.visual.action.AcceptProvider;
import org.netbeans.api.visual.action.ActionFactory;
import org.netbeans.api.visual.action.ConnectProvider;
import org.netbeans.api.visual.action.ConnectorState;
import org.netbeans.api.visual.action.PopupMenuProvider;
import org.netbeans.api.visual.action.WidgetAction;
import org.netbeans.api.visual.model.ObjectSceneEvent;
import org.netbeans.api.visual.model.ObjectSceneEventType;
import org.netbeans.api.visual.model.ObjectSceneListener;
import org.netbeans.api.visual.model.ObjectState;
import org.netbeans.api.visual.vmd.VMDGraphScene;
import org.netbeans.api.visual.vmd.VMDNodeWidget;
import org.netbeans.api.visual.vmd.VMDPinWidget;
import org.netbeans.api.visual.widget.EventProcessingType;
import org.netbeans.api.visual.widget.LayerWidget;
import org.netbeans.api.visual.widget.Scene;
import org.netbeans.api.visual.widget.Widget;
import org.openide.util.Exceptions;
import org.openide.util.Utilities;
import org.put.netbeans.dcs_modeler.palette.*;

/**
 *
 * @author rudy
 */
public class GraphSceneImpl extends VMDGraphScene
{
    private static Integer edgeID = 0;
    //private WidgetAction editorAction = ActionFactory.createInplaceEditorAction( new LabelTextFieldEditor() );
    private LayerWidget mainLayer;
    private LayerWidget connectionLayer;
    private LayerWidget interractionLayer;
    private long edgeCounter = 0; 
    private long nodeCounter = 0;
    public static Integer nodeID = 0;
    private static Logger log =
	    Logger.getLogger( GraphSceneImpl.class.getName() );
    
    
    public GraphSceneImpl() 
    {
        mainLayer = new LayerWidget( this );
        addChild( mainLayer );
        connectionLayer = new LayerWidget( this );
        addChild( connectionLayer );
        getActions().addAction( ActionFactory.createAcceptAction( new AcceptProvider()
        {
              public ConnectorState isAcceptable( Widget widget, Point point, Transferable transferable )
              {
                try
                {
                    WorkflowElement data = ( WorkflowElement ) transferable.getTransferData( PaletteSupport.WORKFLOW_ELEMENT_FLAVOR );
                    if ( !data.isDnd() )
                    {
                        return ConnectorState.REJECT;
                    }
                }
                catch ( UnsupportedFlavorException ex )
                {
                    Exceptions.printStackTrace( ex );
                }
                catch ( IOException ex )
                {
                    Exceptions.printStackTrace( ex );
                }
                Image dragImage = getImageFromTransferable( transferable );
                JComponent view = getView();
                Graphics2D g2 = ( Graphics2D ) view.getGraphics();
                Rectangle visRect = view.getVisibleRect();
                view.paintImmediately( visRect.x, visRect.y, visRect.width, visRect.height );
                g2.drawImage( dragImage, AffineTransform.getTranslateInstance( point.getLocation().getX(), point.getLocation().getY() ), null );
                return ConnectorState.ACCEPT;
                
              }

              public void accept( Widget widget, Point point, Transferable transferable )
              {
                  Image image = getImageFromTransferable( transferable );
                //  Widget w = GraphSceneImpl.this.addNode( node );
                  Point widgetLocation = widget.convertLocalToScene( point );
                  String nodeId = createNode( GraphSceneImpl.this, (int)widgetLocation.getX(), (int)widgetLocation.getY(), image, "test", "List", null );
                  String pinId = nodeId + GraphSceneImpl.this.getNodePins( nodeId ).size();
                  createPin( GraphSceneImpl.this, nodeId, pinId, null, pinId, "Element" );
                  pinId = nodeId + GraphSceneImpl.this.getNodePins( nodeId ).size();
                  createPin( GraphSceneImpl.this, nodeId, pinId, null, pinId, "Element" );
              }
        } ) );
        // zoom 
        getActions().addAction( ActionFactory.createZoomAction() );
        getActions().addAction( ActionFactory.createPanAction() );
        interractionLayer = new LayerWidget( this );
        addChild( interractionLayer );
        SceneObjectListener seneListener = new SceneObjectListener();
        addObjectSceneListener( seneListener, ObjectSceneEventType.values() );
        setKeyEventProcessingType( EventProcessingType.FOCUSED_WIDGET_AND_ITS_CHILDREN_AND_ITS_PARENTS );
        //getActions().addAction( new WidgetActionListener() );
    }

    private String createNode( VMDGraphScene scene, int x, int y, Image image, String name, String type, List<Image> glyphs ) 
    {
        String nodeID = "node" + GraphSceneImpl.nodeID ++;
        VMDNodeWidget widget = ( VMDNodeWidget )scene.addNode( nodeID );
        widget.setPreferredLocation( new Point( x, y ) );
        widget.setNodeProperties( image, name, type, glyphs );
        widget.getActions().addAction( new WidgetActionListener() );
        NodeMenu f = new NodeMenu();
        //scene.addPin( nodeID, nodeID + VMDGraphScene.PIN_ID_DEFAULT_SUFFIX );
        widget.getActions().addAction( ActionFactory.createPopupMenuAction( new PopupMenuProvider() 
        {
            public JPopupMenu getPopupMenu( Widget arg0, Point arg1 )
            {
                
                return new NodeMenu();
            }
        } ) );
        return nodeID;
    }
    
    private void deleteSelectedNode( VMDGraphScene scene )
    {
        Set obj = scene.getSelectedObjects();
        for ( Object tmp : obj )
        {
            if ( scene.isNode( tmp ) )
            {
                scene.removeNodeWithEdges( (String)tmp );
            }
        }
    }

    private void createPin( VMDGraphScene scene, String nodeID, String pinID, Image image, String name, String type ) 
    {
        VMDPinWidget pin = ( VMDPinWidget )scene.addPin( nodeID, pinID );
        pin.setVisible( true );
        pin.setProperties( name, null );
        pin.getActions().addAction( ActionFactory.createConnectAction( this.interractionLayer, new WidgetConnectProvider() ) );
    }
    
     private void createEdge( VMDGraphScene scene, String sourcePinID, String targetNodeID) 
     {
        String edgeID = "edge" + GraphSceneImpl.edgeID ++;
        scene.addEdge( edgeID );
        scene.setEdgeSource( edgeID, sourcePinID );
        scene.setEdgeTarget( edgeID, targetNodeID );

     }     
    
    private Image getImageFromTransferable( Transferable transferable )
    {
        WorkflowElement data = null;
        Image im = null;
        try
        {
            data = ( WorkflowElement )transferable.getTransferData( PaletteSupport.WORKFLOW_ELEMENT_FLAVOR );
            log.info( "!!!!!!!!!!!!!!!!!!! " + data.getImage() );
            if ( data instanceof WorkflowElement )
            {
               // final Image image = (Image) node.getIcon(BeanInfo.ICON_COLOR_16x16);
                im = Utilities.loadImage( data.getImage() );
                log.info("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!zaladowany image!!!!!!!!!!!!!!!!!!!!!!");
            }
        }
        catch ( IOException ex )
        {
            ex.printStackTrace();
        }
        catch ( UnsupportedFlavorException ex )
        {
            ex.printStackTrace();
        }
        return ( im != null ) ? im.getScaledInstance(20, 20, Image.SCALE_AREA_AVERAGING) : Utilities.loadImage( "org/put/netbeans/dcs_modeler/palette/images/workflow_simple_case.png" );
    }
    
    private class SceneObjectListener implements ObjectSceneListener
    {
        private String previousSelection = null;
        private String newSelection = null;
        
        private Logger log =
                Logger.getLogger( SceneObjectListener.class.getName() );

        public void objectAdded( ObjectSceneEvent event, Object addedObject )
        {
            log.info( "addedObject = " + addedObject );
        }

        public void objectRemoved( ObjectSceneEvent event, Object removedObject )
        {
            log.info( "removedObject = " + removedObject );
        }

        public void objectStateChanged( ObjectSceneEvent event, Object changedObject, ObjectState previousState, ObjectState newState )
        {
            log.info( "changedObject = " + changedObject + " | previousState = " + previousState + " | newState = " + newState );
        }

        public void selectionChanged( ObjectSceneEvent event, Set<Object> previousSelection, Set<Object> newSelection )
        {
           
        }

        public void highlightingChanged( ObjectSceneEvent event, Set<Object> previousHighlighting, Set<Object> newHighlighting )
        {
            log.info( "previousHighlighting = " + previousHighlighting + " | newHighlighting = " + newHighlighting );
        }

        public void hoverChanged( ObjectSceneEvent event, Object previousHoveredObject, Object newHoveredObject )
        {
            log.info( "previousHoveredObject = " + previousHoveredObject + " | newHoveredObject = " + newHoveredObject );
        }

        public void focusChanged( ObjectSceneEvent event, Object previousFocusedObject, Object newFocusedObject )
        {
            log.info( "previousFocusedObject = " + previousFocusedObject + " | newFocusedObject = " + newFocusedObject );
        }
    }
    
    public class WidgetActionListener extends WidgetAction.Adapter 
    {

        @Override
        public State mouseClicked( Widget widget, WidgetMouseEvent event )
        {
            log.info( "ooooooooooooooooooooooooooooooooooooooooooooooooooooooo" );
            if ( event.getButton() == MouseEvent.BUTTON3 )
            {
                return State.CONSUMED;
            } else if ( event.getButton() == MouseEvent.BUTTON2 )
            {
                return State.CONSUMED;
            }
            if ( widget instanceof VMDPinWidget )
                log.info( "kupa +++++++++++++++" + ( ( VMDPinWidget ) widget ).getPinName() );
            return State.REJECTED;
        }
        
      

    }
    
    private class NodeMenu extends JPopupMenu
    {
        public NodeMenu()
        {
            JMenuItem item;
            setLabel( "Zarządzanie elementami" );
            add( item = new JMenuItem( "Usuń", new ImageIcon( Utilities.loadImage( "org/put/netbeans/dcs_modeler/menu/images/Restricted.png" ) ) ) );
            item.addActionListener( new ActionListener() 
            {
                public void actionPerformed( ActionEvent e )
                {
                    deleteSelectedNode( GraphSceneImpl.this );
                }
            } );
        }

    }
    
    private class WidgetConnectProvider implements ConnectProvider
    {
        private String source = null;
        private String target = null;
        public boolean isSourceWidget( Widget sourceWidget )
        {
            log.info( "-------------------------------------------------source" );
            Object object = findObject( sourceWidget );
            source = isPin( object ) ? ( String )object : null;
            return source != null;
        }

        public ConnectorState isTargetWidget( Widget sourceWidget, Widget targetWidget )
        {
            log.info( "-------------------------------------------------target" );
            Object object = findObject( targetWidget );
            target = isPin(object) ? (String)object : null;
            if ( target != null )
            {
                return !source.equals( target ) ? ConnectorState.ACCEPT : ConnectorState.REJECT_AND_STOP;
            }
            return object != null ? ConnectorState.REJECT_AND_STOP : ConnectorState.REJECT;
        }

        public boolean hasCustomTargetWidgetResolver( Scene arg0 )
        {
            log.info( "-------------------------------------------------target" );
            return false;
        }

        public Widget resolveTargetWidget( Scene arg0, Point arg1 )
        {
            log.info( "-------------------------------------------------target" );
            return null;
        }

        public void createConnection( Widget arg0, Widget arg1 )
        {
            log.info( "-------------------------------------------------target" );
            String edgeID = "edge" + GraphSceneImpl.edgeID ++;
            addEdge( edgeID );
            setEdgeSource( edgeID, source );
            setEdgeTarget( edgeID, target );
        }
    }
}
